#include "include/mymodbus.h"
#include "include/parammodbus.h"

#include <QDebug>
#include <QModbusRtuSerialMaster>
#include <QModbusTcpClient>
MyModbus::MyModbus( QObject* parent ) : QObject( parent ) {}

MyModbus::~MyModbus() {
    if ( modbusDevice ) { modbusDevice->disconnectDevice(); }
    delete modbusDevice;
}

void MyModbus::onReadModbus( const QModbusDataUnit readRequest ) {
    if ( !modbusDevice ) {
        qDebug() << "onReadModbus null";
        return;
    }
    if ( auto* reply = modbusDevice->sendReadRequest( readRequest, ParamModbus::StatID ) ) {
        if ( !reply->isFinished() ) { connect( reply, &QModbusReply::finished, this, &MyModbus::onReady ); }
        else {
            delete reply;
        }
    }
    else {
        emit sigModbusReadError( modbusDevice->errorString() );
    }
}

void MyModbus::onWriterModbus( const QModbusDataUnit writerRequestconst ) {
    if ( !modbusDevice ) return;
    if ( auto* reply = modbusDevice->sendWriteRequest( writerRequestconst, ParamModbus::StatID ) ) {
        if ( !reply->isFinished() ) {
            connect( reply, &QModbusReply::finished, this, [this, reply]() {
                if ( reply->error() == QModbusDevice::ProtocolError ) {
                    emit sigModbusWriterError( tr( "Write response error: %1 (Mobus exception: 0x%2)" ).arg( reply->errorString() ).arg( reply->rawResult().exceptionCode(), -1, 16 ) );
                }
                else if ( reply->error() != QModbusDevice::NoError ) {
                    emit sigModbusWriterError( tr( "Write response error: %1 (code: 0x%2)" ).arg( reply->errorString() ).arg( reply->error(), -1, 16 ) );
                }
                reply->deleteLater();
            } );
        }
        else {
            reply->deleteLater();
        }
    }
    else {
        emit sigModbusWriterError( tr( "Write error: " ) + modbusDevice->errorString() );
    }
}

void MyModbus::onDisconnct() {
    if ( modbusDevice ) { modbusDevice->disconnectDevice(); }
}

void MyModbus::initModbus() {
    if ( ParamModbus::ModbusType == 1 ) { modbusDevice = new QModbusRtuSerialMaster( this ); }
    if ( ParamModbus::ModbusType == 2 ) { modbusDevice = new QModbusTcpClient( this ); }
    connect( modbusDevice, &QModbusClient::errorOccurred, [this]( QModbusDevice::Error ) { emit sigModbusConnectError( modbusDevice->errorString() ); } );
    if ( modbusDevice ) {
        connect( modbusDevice, &QModbusClient::stateChanged, this, &MyModbus::onModbusStateChanged );
        connectModbus();
    }
}

void MyModbus::connectModbus() {
    if ( !modbusDevice ) { return; }
    if ( modbusDevice->state() != QModbusDevice::ConnectedState ) {
        if ( ParamModbus::ModbusType == 1 ) {
            //串口名
            modbusDevice->setConnectionParameter( QModbusDevice::SerialPortNameParameter, ParamModbus::SerialPortNameParameter );
            //奇偶校验
            modbusDevice->setConnectionParameter( QModbusDevice::SerialParityParameter, ParamModbus::SerialParityParameter );
            //波特率
            modbusDevice->setConnectionParameter( QModbusDevice::SerialBaudRateParameter, ParamModbus::SerialBaudRateParameter );
            //串行数据位
            modbusDevice->setConnectionParameter( QModbusDevice::SerialDataBitsParameter, ParamModbus::SerialDataBitsParameter );
            //停止位
            modbusDevice->setConnectionParameter( QModbusDevice::SerialStopBitsParameter, ParamModbus::SerialStopBitsParameter );
        }
        if ( ParamModbus::ModbusType == 2 ) {
            modbusDevice->setConnectionParameter( QModbusDevice::NetworkAddressParameter, ParamModbus::TcpIP );
            modbusDevice->setConnectionParameter( QModbusDevice::NetworkPortParameter, ParamModbus::TcpPort );
        }
    }
    modbusDevice->setTimeout( ParamModbus::SerialTimeout );
    if ( !modbusDevice->connectDevice() ) { emit sigModbusConnectSuccesful(); }
}

void MyModbus::onModbusStateChanged( int state ) {
    qDebug() << "onModbusStateChanged" << state;
    emit sigModbusStateChanged( state );
}

void MyModbus::onReady() {
    auto reply = qobject_cast< QModbusReply* >( sender() );
    if ( !reply ) return;
    if ( reply->error() == QModbusDevice::NoError ) {
        const QModbusDataUnit unit = reply->result();
        emit                  sigModbusReady( unit );
    }
    else if ( reply->error() == QModbusDevice::ProtocolError ) {
        emit sigModbusReadError( tr( "Read response error: %1 (Mobus exception: 0x%2)" ).arg( reply->errorString() ).arg( reply->rawResult().exceptionCode(), -1, 16 ) );
    }
    else {
        emit sigModbusReadError( tr( "Read response error: %1 (code: 0x%2)" ).arg( reply->errorString() ).arg( reply->error(), -1, 16 ) );
    }
    reply->deleteLater();
}
